package top.zhangjianyong.blog.utils;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import java.util.Optional;
import java.util.concurrent.locks.ReentrantLock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import top.zhangjianyong.blog.enums.SessionKey;

/**
 * session工具类
 *
 * @author zhangjianyong
 * @since 2024/7/19 下午8:13
 */
@Slf4j
public class SessionUtil {

  public static HttpSession getSession() {
    ServletRequestAttributes requestAttributes =
        (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    if (requestAttributes == null) return null;
    HttpServletRequest request = requestAttributes.getRequest();
    return request.getSession();
  }

  public static <T> T get(SessionKey key, Class<T> clazz) {
    return get(key, clazz, null);
  }

  public static <T> T get(SessionKey key, Class<T> clazz, T def) {
    return Optional.ofNullable(getSession())
        .map(session -> session.getAttribute(key.getCode()))
        .map(
            o -> {
              try {
                return clazz.cast(o);
              } catch (ClassCastException e) {
                log.error(e.getMessage(), e);
                return def;
              }
            })
        .orElse(def);
  }

  public static void set(SessionKey key, Object value) {
    Optional.ofNullable(getSession())
        .ifPresent(session -> session.setAttribute(key.getCode(), value));
  }

  public static String getId() {
    return Optional.ofNullable(getSession()).map(HttpSession::getId).orElse("");
  }

  public static ReentrantLock getLock() {
    HttpSession session = getSession();
    if (null == session) {
      log.warn("session is null, returning a new ReentrantLock");
      return new ReentrantLock();
    }
    synchronized (session) {
      ReentrantLock look = SessionUtil.get(SessionKey.SESSION_LOCK, ReentrantLock.class);
      if (look == null) {
        look = new ReentrantLock();
        set(SessionKey.SESSION_LOCK, look);
      }
      return look;
    }
  }

  public static void remove(SessionKey key) {
    Optional.ofNullable(getSession()).ifPresent(session -> session.removeAttribute(key.getCode()));
  }
}
